package com.yueka.service.Impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import com.yueka.service.AliOssService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.utils.StringUtils;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.dromara.x.file.storage.core.constant.Constant;
import org.dromara.x.file.storage.core.get.RemoteFileInfo;
import org.dromara.x.file.storage.core.presigned.GeneratePresignedUrlResult;
import org.dromara.x.file.storage.core.upload.UploadPretreatment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Date;

@Slf4j
@Service
public class AliOssServiceImpl implements AliOssService {

    @Resource
    private FileStorageService fileStorageService;

    @Override
    public String uploadFile(MultipartFile file) {
        UploadPretreatment pretreatment = fileStorageService.of(file);
        FileInfo fileInfo = pretreatment.upload();
        return fileInfo.getUrl();
    }

    @Override
    public GeneratePresignedUrlResult clientUpload() {
        GeneratePresignedUrlResult uploadResult = fileStorageService
                .generatePresignedUrl()
                // 设置路径
//                .setPath()
                // 设置保存的文件名
//                .setFilename(param.getFileName())
                // 签名方法
                .setMethod(Constant.GeneratePresignedUrl.Method.PUT)
                // 设置过期时间 10 分钟
                .setExpiration(DateUtil.offsetMinute(new Date(), 10))
                // 设置要上传文件 MIME 类型
                .putHeaders(Constant.Metadata.CONTENT_TYPE, "application/octet-stream")
                .generatePresignedUrl();
        log.info("生成上传预签名 URL 结果：{}", uploadResult);
        return uploadResult;
    }

    @Override
    public String getSignUrl(String url) {
        // 从URL中提取OSS key路径
        String ossKey = extractOssKeyFromUrl(url);
        FileInfo fileInfo = new FileInfo().setPlatform("aliyun-oss").setPath(ossKey);
        //直接返回
        return fileStorageService.generatePresignedUrl(fileInfo, DateUtil.offsetHour(new Date(), 1));
    }

    @Override
    public String preSign(String uri) {
        FileInfo fileInfo = getFileInfoByUri(uri);
        //判断文件是否存在
        boolean exists = fileStorageService.exists(fileInfo);
        log.info("------ 文件是否存在 >> {}", exists);
        if (Boolean.TRUE.equals(exists)) {
            //直接返回
            return fileStorageService.generatePresignedUrl(fileInfo, DateUtil.offsetHour(new Date(), 1));
        }
        fileInfo.setFilename(fileInfo.getFilename().replace("null", ""));
        String fileName = fileInfo.getFilename();
        // 裁剪图片
        if (fileName.contains("@s")) {
            return cutImage(fileInfo);
        }
        //压缩
        if (fileName.contains("@compress")) {
            return compressImage(fileInfo);
        }
        throw new RuntimeException("文件不存在!");
    }

    @Override
    public FileInfo getFileInfoByUri(String uri) {
        log.info("------ 根据Uri获取FileInfo >> 入参：{}", uri);
        // 提取 'preSign/' 之后的部分
        String endUrl = uri.substring(uri.indexOf("/preSign/") + "/preSign/".length());
        int lastIndex = endUrl.lastIndexOf("/");
        FileInfo fileInfo = new FileInfo();
        // 提取路径部分
        fileInfo.setPath(endUrl.substring(0, lastIndex + 1));
        // 提取文件名部分
        String fileName = endUrl.substring(lastIndex + 1);
        fileInfo.setFilename(fileName);
        fileInfo.setPlatform("aliyun-oss");
        if (fileName.contains("@s") || fileName.contains("@compress")) {
            fileInfo.setFilename(fileName + "null");
        }
        log.info("------ 根据Uri获取FileInfo >> 出参：{}", JSONUtil.toJsonStr(fileInfo));
        return fileInfo;
    }

    /**
     * 裁剪图片
     */
    private String cutImage(FileInfo fileInfo) {
        String fileName = fileInfo.getFilename();
        String sourceName = fileName.split("@s")[0];
        String size = fileName.split("@s")[1];
        int width = Integer.parseInt(size.split("x")[0]);
        int height = Integer.parseInt(size.split("x")[1]);
        // 下载源文件为字节数组
        fileInfo.setFilename(sourceName);
        byte[] bytes = fileStorageService.download(fileInfo).bytes();
        log.info("------  >> 下载源文件为字节数组");
        // 对图片进行处理并上传，有多个重载方法。图片处理使用的是 https://github.com/coobird/thumbnailator
        FileInfo thFile = fileStorageService.of(bytes)
                .setPath(fileInfo.getPath())
                //指定缩略图后缀，必须是 thumbnailator 支持的图片格式，默认使用全局的
                .setThumbnailSuffix(null)
                //指定缩略图的保存文件名，注意此文件名不含后缀，默认自动生成
                .setSaveThFilename(fileName)
                // 生成一张缩略图
                .thumbnail(th -> th.size(width, height))
                .upload();
        log.info("------ 生成一张缩略图 >> {}", JSONUtil.toJsonStr(thFile));
        thFile.setFilename(thFile.getThFilename());
        return fileStorageService.generatePresignedUrl(thFile, DateUtil.offsetHour(new Date(), 1));
    }

    /**
     * 压缩图片
     *
     * @param fileInfo
     * @return
     */
    private String compressImage(FileInfo fileInfo) {
        String fileName = fileInfo.getFilename();
        String sourceName = fileInfo.getFilename().split("@compress")[0];
        fileInfo.setFilename(sourceName);
        // 定义 200K 的字节数
        final long maxSize = 500 * 1024;
        // 下载源文件为字节数组
        fileInfo.setFilename(sourceName);
        byte[] bytes = fileStorageService.download(fileInfo).bytes();
        if (bytes.length < maxSize) {
            //直接返回
            return fileStorageService.generatePresignedUrl(fileInfo, DateUtil.offsetHour(new Date(), 1));
        }
        //通过 FileInfo 获取文件信息
        RemoteFileInfo info = fileStorageService.getFile(fileInfo);
        //获取图片宽高
        URL url = URLUtil.url(info.getUrl());
        BufferedImage image = ImgUtil.read(url);
        if (ObjectUtil.isNull(image)) {
            throw new RuntimeException("获取图片宽高失败！");
        }
        int width = image.getWidth();
        int height = image.getHeight();
        // 对图片进行处理并上传，有多个重载方法。图片处理使用的是 https://github.com/coobird/thumbnailator
        FileInfo thFile = fileStorageService.of(bytes)
                .setPath(fileInfo.getPath())
                //指定缩略图后缀，必须是 thumbnailator 支持的图片格式，默认使用全局的
                .setThumbnailSuffix(null)
                //指定缩略图的保存文件名，注意此文件名不含后缀，默认自动生成
                .setSaveThFilename(fileName)
                .image(img -> {
                    //压缩图片
                    img.scale(1);
                    // 压缩质量
                    img.outputQuality(0.5f);
                })
                .thumbnail(th -> th.size(width, height))
                .upload();
        thFile.setFilename(thFile.getThFilename());
        return fileStorageService.generatePresignedUrl(thFile, DateUtil.offsetHour(new Date(), 1));
    }

    /**
     * 从URL中提取OSS key路径
     * 例如: https://xxxx.com/api/resource/file/preSign/image/68517796c9212e785da20d2c.pdf
     * 提取出: image/68517796c9212e785da20d2c.pdf
     */
    private String extractOssKeyFromUrl(String url) {
        try {
            if (StringUtils.isBlank(url)) {
                return null;
            }
            // 查找最后一个 '/' 前的路径部分
            int preSignIndex = url.indexOf("/preSign/");
            if (preSignIndex > 0) {
                String keyPart = url.substring(preSignIndex + "/preSign/".length());
                log.info("从URL提取的OSS key: {}", keyPart);
                return keyPart;
            }

            return null;
        } catch (Exception e) {
            log.warn("提取OSS key失败: {}", e.getMessage());
            return null;
        }
    }
}
